package com.hj.tools;

import cn.hutool.core.codec.Base64;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.hj.model.TenCentDataBO;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.MultiObjectDeleteException;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.faceid.v20180301.FaceidClient;
import com.tencentcloudapi.faceid.v20180301.models.IdCardVerificationRequest;
import com.tencentcloudapi.faceid.v20180301.models.IdCardVerificationResponse;
import com.tencentcloudapi.sms.v20190711.SmsClient;
import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author < a href="huajian2018@aliyun.com">hj</ a>
 * @Description  腾讯相关工具类
 */
@Component
public class TenCentCloudUtil {

    private final Logger log = LoggerFactory.getLogger(TenCentCloudUtil.class);

    //腾讯短信,身份认证

    @Value("${tenCent.smsSecretId}")
    private String smsSecretId;
    @Value("${tenCent.smsSecretKey}")
    private String smsSecretKey;
    @Value("${tenCent.appId}")
    private String appId;
    @Value("${tenCent.sign}")
    private String sign;
    //验证码模板ID

    @Value("${tenCent.templateID}")
    private String templateID;
    @Value("${tenCent.minTime}")
    private String minTime;

    //企业认证

    @Value("${tenCent.authSecretId}")
    private String authSecretId;
    @Value("${tenCent.authSecretKey}")
    private String authSecretKey;
    @Value("${tenCent.source}")
    private String source;

    //对象存储

    @Value("${tenCent.cosSecretId}")
    private String cosSecretId;
    @Value("${tenCent.cosSecretKey}")
    private String cosSecretKey;
    @Value("${tenCent.cosRegion}")
    private String cosRegion;
    @Value("${tenCent.cosBucketName}")
    private String cosBucketName;
    @Value("${tenCent.cosPathPrefix}")
    private String cosPathPrefix;


//4对象存储

    /**
     * cos上传文件
     *
     * @param file 文件
     * @return 路径
     */
    public String cosUpload(File file) {
        // 1 初始化用户身份信息(secretId, secretKey)
        COSCredentials cred = new BasicCOSCredentials(cosSecretId, cosSecretKey);
        // 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
        ClientConfig clientConfig = new ClientConfig(new Region(cosRegion));
        // 3 生成cos客户端
        COSClient cosclient = new COSClient(cred, clientConfig);
        String fileName = file.getName();
        String key = System.currentTimeMillis() + fileName;
        PutObjectRequest putObjectRequest = new PutObjectRequest(cosBucketName, key, file);
        // 限流使用的单位是bit/s, 这里测试1MB/s的上传带宽限制
        putObjectRequest.setTrafficLimit(1024 * 1024);
        // 设置存储类型, 默认是标准(Standard), 低频(standard_ia)
        putObjectRequest.setStorageClass(StorageClass.Standard);
        try {
            PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest);
            log.info("cos对象存储返回结果:{}", putObjectResult.getRequestId());
            String path = cosPathPrefix + key;
            log.info("cos存储路径:{}", path);
            return path;
        } catch (CosClientException e) {
            log.error("cos对象存储异常:{}", e.getMessage());
            return null;
        } finally {
            // 关闭客户端
            cosclient.shutdown();
        }
    }

    //cos删除文件
    public Boolean cosDelete(String path) {
        COSCredentials cred = new BasicCOSCredentials(cosSecretId, cosSecretKey);
        ClientConfig clientConfig = new ClientConfig(new Region(cosRegion));
        COSClient cosclient = new COSClient(cred, clientConfig);
        DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(cosBucketName);
        // 设置要删除的key列表, 最多一次删除1000个
        ArrayList<DeleteObjectsRequest.KeyVersion> keyList = new ArrayList<>();
        // 传入要删除的文件名
        keyList.add(new DeleteObjectsRequest.KeyVersion(path.substring(path.lastIndexOf("com") + 4)));
        deleteObjectsRequest.setKeys(keyList);
        // 批量删除文件
        try {
            DeleteObjectsResult deleteObjectsResult = cosclient.deleteObjects(deleteObjectsRequest);
            List<DeleteObjectsResult.DeletedObject> deleteObjectResultArray = deleteObjectsResult.getDeletedObjects();
            return !deleteObjectResultArray.isEmpty();
        } catch (MultiObjectDeleteException mde) { // 如果部分产出成功部分失败, 返回MultiObjectDeleteException
            List<DeleteObjectsResult.DeletedObject> deleteObjects = mde.getDeletedObjects();
            List<MultiObjectDeleteException.DeleteError> deleteErrors = mde.getErrors();
            log.error("cos对象存储删除部分成功部分失败:" + deleteObjects + ",\n" + deleteErrors);
            return false;
        } catch (CosClientException e) { // 如果是其他错误, 比如参数错误， 身份验证不过等会抛出CosServiceException
            log.error("cos对象存储删除文件异常:{}", e.getMessage());
            return false;
        } finally {
            cosclient.shutdown();
        }
    }


//1-腾讯短信发送封装方法

    //1-1发送短信验证码
    public boolean sendVerifyCode(String[] phones, String verifyCode) {
        try {
            Credential cred = new Credential(smsSecretId, smsSecretKey);
            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setReqMethod("POST");
            httpProfile.setConnTimeout(60);
            ClientProfile clientProfile = new ClientProfile();
            /* SDK 默认用 TC3-HMAC-SHA256 进行签名
             * 非必要请不要修改该字段 */
            clientProfile.setSignMethod("HmacSHA256");
            clientProfile.setHttpProfile(httpProfile);
            /* 实例化 SMS 的 client 对象
             * 第二个参数是地域信息，可以直接填写字符串 ap-guangzhou，或者引用预设的常量 */
            SmsClient client = new SmsClient(cred, "", clientProfile);
            SendSmsRequest req = new SendSmsRequest();
            req.setSmsSdkAppid(appId);
            req.setSign(sign);
            req.setTemplateID(templateID);
            req.setPhoneNumberSet(phones);
            /* 模板参数: 若无模板参数，则设置为空*/
            String[] templateParams = {verifyCode, minTime};
            req.setTemplateParamSet(templateParams);
            SendSmsResponse res = client.SendSms(req);
            // 输出 JSON 格式的字符串回包
            String s = SendSmsResponse.toJsonString(res);
            System.err.println(s);
            // 可以取出单个值，您可以通过官网接口文档或跳转到 response 对象的定义处查看返回字段的定义
            System.out.println(res.getRequestId());
            return s.contains("send success");

        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return false;
    }


//2-腾讯企业认证封装方法

    public TenCentDataBO auth(String enterpriseName) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {

        Calendar cd = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        String datetime = sdf.format(cd.getTime());
        // 签名
        String auth = calcAuthorization(source, authSecretId, authSecretKey, datetime);
        // 请求方法
        String method = "GET";
        // 请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("X-Source", source);
        headers.put("X-Date", datetime);
        headers.put("Authorization", auth);

        // 查询参数
        Map<String, String> queryParams = new HashMap<>(1);
        //企业名称
        queryParams.put("name", enterpriseName);
        // body参数
        Map<String, String> bodyParams = new HashMap<>();
        // url参数拼接
        String url = "http://service-p14a7xcb-1255468759.ap-shanghai.apigateway.myqcloud.com/release/1672-4";
        if (!queryParams.isEmpty()) {
            url += "?" + urlencode(queryParams);
        }

        BufferedReader in = null;
        try {
            URL realUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            conn.setRequestMethod(method);
            // request headers
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                conn.setRequestProperty(entry.getKey(), entry.getValue());
            }
            // request body
            Map<String, Boolean> methods = new HashMap<>();
            methods.put("POST", true);
            methods.put("PUT", true);
            methods.put("PATCH", true);
            Boolean hasBody = methods.get(method);
            if (hasBody != null) {
                conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                conn.setDoOutput(true);
                DataOutputStream out = new DataOutputStream(conn.getOutputStream());
                out.writeBytes(urlencode(bodyParams));
                out.flush();
                out.close();
            }
            // 定义 BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            StringBuilder result = new StringBuilder();
            while ((line = in.readLine()) != null) {
                result.append(line);
            }

            JSONObject jsonObject = JSONUtil.parseObj(result.toString());
            Object showapi_res_body = jsonObject.get("showapi_res_body");
            String jsonString = JSON.toJSONString(showapi_res_body);
            TenCentDataBO tenCentDataModel = JSON.parseObject(jsonString, TenCentDataBO.class);
            //查询成功
            if (null != tenCentDataModel && tenCentDataModel.getMsgCode().equals("0")) {
                return tenCentDataModel;
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return null;
    }

    private String calcAuthorization(String source, String secretId, String secretKey, String datetime)
            throws NoSuchAlgorithmException, InvalidKeyException {
        String signStr = "x-date: " + datetime + "\n" + "x-source: " + source;
        Mac mac = Mac.getInstance("HmacSHA1");
        Key sKey = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), mac.getAlgorithm());
        mac.init(sKey);
        byte[] hash = mac.doFinal(signStr.getBytes(StandardCharsets.UTF_8));
        String sig = Base64.encode(hash);
        String auth = "hmac id=\"" + secretId + "\", algorithm=\"hmac-sha1\", headers=\"x-date x-source\", signature=\"" + sig + "\"";
        System.out.println(auth);
        return auth;
    }

    private String urlencode(Map<?, ?> map) throws UnsupportedEncodingException {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<?, ?> entry : map.entrySet()) {
            if (sb.length() > 0) {
                sb.append("&");
            }
            sb.append(String.format("%s=%s",
                    URLEncoder.encode(entry.getKey().toString(), "UTF-8"),
                    URLEncoder.encode(entry.getValue().toString(), "UTF-8")
            ));
        }
        return sb.toString();
    }


//3身份证认证

    public IdCardVerificationResponse IdCardAuth(String idCard, String name) throws TencentCloudSDKException {
        Credential cred = new Credential(smsSecretId, smsSecretKey);

        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("faceid.ap-guangzhou.tencentcloudapi.com");

        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);

        FaceidClient client = new FaceidClient(cred, "ap-guangzhou", clientProfile);

        String params = "{\"IdCard\":\"" + idCard + "\",\"Name\":\"" + name + "\"}";
        IdCardVerificationRequest req = IdCardVerificationRequest.fromJsonString(params, IdCardVerificationRequest.class);

        IdCardVerificationResponse resp = client.IdCardVerification(req);
        //返回 Result:-2非法 -1姓名和身份证号不一致 0 姓名和身份证号一致
        System.out.println(IdCardVerificationRequest.toJsonString(resp));
        return resp;
    }


}
